package com.dm.cloud.databases.redis;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.RedissonMultiLock;
import org.redisson.RedissonRedLock;
import org.redisson.api.*;
import org.redisson.config.Config;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class RedissionUtils {

    private static RedissionUtils redisUtils;

    private RedissionUtils() {
    }

    /**
     * 提供单例模式
     *
     * @return
     */
    public static RedissionUtils getInstance() {
        if (redisUtils == null)
            synchronized (RedissionUtils.class) {
                if (redisUtils == null)
                    redisUtils = new RedissionUtils();
            }
        return redisUtils;
    }

    /**
     * 使用config创建Redisson Redisson是用于连接Redis Server的基础类
     *
     * @param config
     * @return
     */
    public RedissonClient getRedisson(Config config) {
        RedissonClient redisson = Redisson.create(config);
        log.info("成功连接Redis Server");
        return redisson;
    }

    /**
     * 使用ip地址和端口创建Redisson
     *
     * @param ip
     * @param port
     * @return
     */
    public RedissonClient getRedisson(String ip, String port) {
        Config config = new Config();
        config.useSingleServer().setAddress(ip + ":" + port);
        RedissonClient redisson = Redisson.create(config);
        log.info("成功连接Redis Server" + "\t" + "连接" + ip + ":" + port + "服务器");
        return redisson;
    }

    /**
     * 关闭Redisson客户端连接
     *
     * @param redisson
     */
    public void closeRedisson(RedissonClient redisson) {
        redisson.shutdown();
        log.info("成功关闭Redis Client连接");
    }

    /**
     * 获取字符串对象
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public <T> RBucket<T> getRBucket(RedissonClient redisson, String objectName) {
        RBucket<T> bucket = redisson.getBucket(objectName);
        return bucket;
    }

    /**
     * 获取Map对象
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public <K, V> RMap<K, V> getRMap(RedissonClient redisson, String objectName) {
        RMap<K, V> map = redisson.getMap(objectName);
        return map;
    }

    /**
     * 获取有序集合
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public <V> RSortedSet<V> getRSortedSet(RedissonClient redisson,
                                           String objectName) {
        RSortedSet<V> sortedSet = redisson.getSortedSet(objectName);
        return sortedSet;
    }

    /**
     * 获取集合
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public <V> RSet<V> getRSet(RedissonClient redisson, String objectName) {
        RSet<V> rSet = redisson.getSet(objectName);
        return rSet;
    }

    /**
     * 获取列表
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public <V> RList<V> getRList(RedissonClient redisson, String objectName) {
        RList<V> rList = redisson.getList(objectName);
        return rList;
    }

    /**
     * 获取队列
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public <V> RQueue<V> getRQueue(RedissonClient redisson, String objectName) {
        RQueue<V> rQueue = redisson.getQueue(objectName);
        return rQueue;
    }

    /**
     * 获取双端队列
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public <V> RDeque<V> getRDeque(RedissonClient redisson, String objectName) {
        RDeque<V> rDeque = redisson.getDeque(objectName);
        return rDeque;
    }

    /**
     * 获取阻塞队列
     *
     * @param redisson
     * @param objectName
     * @return
     */
     public <V> RBlockingQueue<V> getRBlockingQueue(RedissonClient redisson,String objectName)
     { RBlockingQueue rb=redisson.getBlockingQueue(objectName); return rb; }

    /**
     * 获取原子数
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public RAtomicLong getRAtomicLong(RedissonClient redisson, String objectName) {
        RAtomicLong rAtomicLong = redisson.getAtomicLong(objectName);
        return rAtomicLong;
    }

    /**
     * 获取记数锁
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public RCountDownLatch getRCountDownLatch(RedissonClient redisson,
                                              String objectName) {
        RCountDownLatch rCountDownLatch = redisson
                .getCountDownLatch(objectName);
        return rCountDownLatch;
    }

    /**
     * 获取消息的Topic
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public RTopic getRTopic(RedissonClient redisson, String objectName) {
        RTopic rTopic = redisson.getTopic(objectName);
        return rTopic;
    }

    //***********************************************************************************
    // LOCK
    //***********************************************************************************
    /**
     * 可重入锁
     * 1、锁定十秒后自动解锁
     * lock.lock(10, TimeUnit.SECONDS);
     *
     * 2、尝试加锁 最多等待100秒 获得到锁之后10秒自动释放
     * boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
     * if (res) {
     *    try {
     *      ...
     *    } finally {
     *        lock.unlock();
     *    }
     * }
     *
     * 3. 支持异步加锁lockAsync
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public RLock getRLock(RedissonClient redisson, String objectName) {
        RLock rLock = redisson.getLock(objectName);
        return rLock;
    }

    /**
     * 公平锁
     * @param redisson
     * @param objectName
     * @return
     */
    public RLock getFairLock(RedissonClient redisson, String objectName) {
        RLock fairLock = redisson.getFairLock(objectName);
        return fairLock;
    }

    /**
     * 获取联锁
     * 可以是不同redis实例上的锁
     * 只有当所有的锁都获取到的时候能使真正的获取到锁
     * @param redisson
     * @param objectName
     * @return
     */
    public RedissonMultiLock getRedissonMultiLock(RedissonClient redisson, String... objectName) {

        List<RLock> rlockList =new ArrayList<>();

        if(objectName.length>0){
            for(String objectN : objectName){
                //单机实例实现联锁
                RLock lock = redisson.getLock("lock1");
                rlockList.add(lock);
            }
        }else{
            throw new RuntimeException("请设置加锁元素");
        }

        RedissonMultiLock redissonMultiLock = new RedissonMultiLock(rlockList.toArray(new RLock[rlockList.size()]));

        return redissonMultiLock;
    }

    /**
     * 获取红锁 与联锁类似
     * 可以是不同redis实例上的锁
     * 当大部分锁都获取到的时候能使真正的获取到锁
     * @param redisson
     * @param objectName
     * @return
     */
    public RedissonRedLock getRedissonRedLock(RedissonClient redisson, String... objectName) {

        List<RLock> rlockList =new ArrayList<>();

        if(objectName.length>0){
            for(String objectN : objectName){
                //单机实例实现联锁
                RLock lock = redisson.getLock("lock1");
                rlockList.add(lock);
            }
        }else{
            throw new RuntimeException("请设置加锁元素");
        }

        RedissonRedLock redissonRedLock = new RedissonRedLock(rlockList.toArray(new RLock[rlockList.size()]));

        return redissonRedLock;
    }

    /**
     * 读写锁
     * rwlock.readLock().lock();获取读锁
     * rwlock.writeLock().lock();获取写锁
     * 可设置自动解锁和尝试加锁
     * @param redisson
     * @param objectName
     * @return
     */
    public RReadWriteLock  getRReadWriteLock (RedissonClient redisson, String objectName) {
        RReadWriteLock  rReadWriteLock  =redisson.getReadWriteLock(objectName);
        return rReadWriteLock;
    }

    /**
     * 获取信号量
     * semaphore.acquire();
     * semaphore.release();
     * @param redisson
     * @param objectName
     * @return
     */
    public RSemaphore getRSemaphore (RedissonClient redisson, String objectName) {
        RSemaphore  rSemaphore  =redisson.getSemaphore(objectName);
        return rSemaphore;
    }
}